#include "ble_scan.h"
#include "timer.h"
#include "flash.h"

static const char *TAG = "ble_scan";
int32_t remote_addr;

uint32_t combine(uint8_t a,uint8_t b,uint8_t c)
{
    return a<<16|b<<8|c;
}

void remote_process(uint8_t *ble_adv,uint8_t adv_data_len)
{
    uint8_t cnt=0;
    uint8_t empty=0;
    bool repetition=true;
    bool addr_valid=false;

    esp_timer_start_once(ble_scan_timer, 200000);            

    do{
        if(!ble_scan_end) break;
        ble_scan_end=false;
        ESP_LOGI(TAG, "scan success");
        esp_log_buffer_hex(TAG, &ble_adv[0], adv_data_len);

        if(ble_adv[10]==0XFF&&ble_adv[11]==0XFF&&ble_adv[12]==0XFF&&ble_adv[13]==0XFe&&ble_adv[14]==0X10)   //对码
        {
            if(pairing_timeout) break;

            if(ble_remote_num==0)
            {
                ble_remote_num++;
                ble_remote_num_set(ble_remote_num);
                remote_addr=combine(ble_adv[15],ble_adv[16],ble_adv[17]);
                remote_addr_set(remote_addr,1);
                printf("pairing_success\r\n");
            }
            else
            {
                cnt=0;
                for(uint8_t i=1;i<255;i++)
                {
                    remote_addr=remote_addr_get(i);
                    if(remote_addr==-1) break;
                    if(remote_addr!=0)
                    {
                        if(remote_addr==combine(ble_adv[15],ble_adv[16],ble_adv[17])) 
                        {
                            repetition=true;
                            break;
                        }
                        cnt++; 
                        if(cnt>=ble_remote_num)
                        {
                            repetition=false;
                            if(empty==0)
                            empty=i+1;
                            break;
                        }
                    }
                    else
                    {
                        if(empty==0)
                        empty=i;
                    }
                }
                if(repetition) break;
                ble_remote_num++;
                ble_remote_num_set(ble_remote_num);
                remote_addr=combine(ble_adv[15],ble_adv[16],ble_adv[17]);
                remote_addr_set(remote_addr,empty);
                printf("pairing_success\r\n");
            }
        }

        if(ble_adv[10]==0XFF&&ble_adv[11]==0XFF&&ble_adv[12]==0XFF&&ble_adv[13]==0XFe&&ble_adv[14]==0X11)   //清码
        {
            if(pairing_timeout) break;
            cnt=0;
            for(uint8_t i=1;i<255;i++)
            {
                remote_addr=remote_addr_get(i);
                if(remote_addr==-1) break;
                if(remote_addr!=0) cnt++;
                if(remote_addr==combine(ble_adv[15],ble_adv[16],ble_adv[17]))
                {
                    ble_remote_num--;
                    ble_remote_num_set(ble_remote_num);
                    remote_addr=0;
                    remote_addr_set(remote_addr,i);      
                    printf("pairing_clean\r\n");   
                    break;           
                }
                if(cnt>=ble_remote_num) break;
            }
        }

        if(ble_remote_num==0) break;
        cnt=0;
        for(int i=1;i<=255;i++)
        {
            remote_addr=remote_addr_get(i);
            if(remote_addr==-1) break;
            if(remote_addr!=0) cnt++;
            if(remote_addr==combine(ble_adv[10],ble_adv[11],ble_adv[12]))
            {
                addr_valid=true;
                break;
            }
            if(cnt>=ble_remote_num) break;
        }

        if(addr_valid)
        {
            //输入控制逻辑
        }

    }while (0);  
}


/* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */
static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
    [PROFILE_A_APP_ID] = {
        .gattc_cb = gattc_profile_event_handler,
        .gattc_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
    },
};

static esp_ble_scan_params_t ble_scan_params = {
    .scan_type              = BLE_SCAN_TYPE_ACTIVE,
    .own_addr_type          = BLE_ADDR_TYPE_PUBLIC,
    .scan_filter_policy     = BLE_SCAN_FILTER_ALLOW_ALL,
    .scan_interval          = 0x50,
    .scan_window            = 0x30,
    .scan_duplicate         = BLE_SCAN_DUPLICATE_DISABLE
};


 void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
{
    if(event==ESP_GATTC_REG_EVT){
        esp_ble_gap_set_scan_params(&ble_scan_params);
    }
}

 void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    switch (event) {
    case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
        //the unit of the duration is second
        uint32_t duration = 0xFFFFFFFF;
        esp_ble_gap_start_scanning(duration);
        break;
    }
    case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
        //scan start complete event to indicate scan start successfully or failed
        if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
            ESP_LOGE(TAG, "scan start failed, error status = %x", param->scan_start_cmpl.status);
            break;
        }
        ESP_LOGI(TAG, "scan start success");

        break;
    case ESP_GAP_BLE_SCAN_RESULT_EVT: {
        esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
        switch (scan_result->scan_rst.search_evt) {
        case ESP_GAP_SEARCH_INQ_RES_EVT:
            if (scan_result->scan_rst.adv_data_len > 0) {
                if (scan_result->scan_rst.ble_adv[0] == 0x16 && scan_result->scan_rst.ble_adv[1] == 0xff && scan_result->scan_rst.ble_adv[2] == 0x4e && scan_result->scan_rst.ble_adv[3] == 0x00 && scan_result->scan_rst.ble_adv[4] == 0x7f && scan_result->scan_rst.ble_adv[5] == 0xff)
                {
                    remote_process(scan_result->scan_rst.ble_adv,scan_result->scan_rst.adv_data_len);
                }
            }

            break;
        case ESP_GAP_SEARCH_INQ_CMPL_EVT:
            break;
        default:
            break;
        }
        break;
    }

    case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
        if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
            ESP_LOGE(TAG, "scan stop failed, error status = %x", param->scan_stop_cmpl.status);
            break;
        }
        ESP_LOGI(TAG, "stop scan successfully");
        break;

    case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
        if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
            ESP_LOGE(TAG, "adv stop failed, error status = %x", param->adv_stop_cmpl.status);
            break;
        }
        ESP_LOGI(TAG, "stop adv successfully");
        break;
    case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
         ESP_LOGI(TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
                  param->update_conn_params.status,
                  param->update_conn_params.min_int,
                  param->update_conn_params.max_int,
                  param->update_conn_params.conn_int,
                  param->update_conn_params.latency,
                  param->update_conn_params.timeout);
        break;
    default:
        break;
    }
}

 void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
{
    /* If event is register event, store the gattc_if for each profile */
    if (event == ESP_GATTC_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            gl_profile_tab[param->reg.app_id].gattc_if = gattc_if;
        } else {
            ESP_LOGI(TAG, "reg app failed, app_id %04x, status %d",
                    param->reg.app_id,
                    param->reg.status);
            return;
        }
    }

    /* If the gattc_if equal to profile A, call profile A cb handler,
     * so here call each profile's callback */
    do {
        int idx;
        for (idx = 0; idx < PROFILE_NUM; idx++) {
            if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
                    gattc_if == gl_profile_tab[idx].gattc_if) {
                if (gl_profile_tab[idx].gattc_cb) {
                    gl_profile_tab[idx].gattc_cb(event, gattc_if, param);
                }
            }
        }
    } while (0);
}


void ble_remote_init(void)
{
    esp_log_level_set(TAG, ESP_LOG_INFO);
    ble_remote_num=ble_remote_num_get();

    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));

    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    esp_err_t ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret) {
        ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_init();
    if (ret) {
        ESP_LOGE(TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_enable();
    if (ret) {
        ESP_LOGE(TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    //register the  callback function to the gap module
    ret = esp_ble_gap_register_callback(esp_gap_cb);
    if (ret){
        ESP_LOGE(TAG, "%s gap register failed, error code = %x\n", __func__, ret);
        return;
    }

    //register the callback function to the gattc module
    ret = esp_ble_gattc_register_callback(esp_gattc_cb);
    if(ret){
        ESP_LOGE(TAG, "%s gattc register failed, error code = %x\n", __func__, ret);
        return;
    }

    ret = esp_ble_gattc_app_register(PROFILE_A_APP_ID);
    if (ret){
        ESP_LOGE(TAG, "%s gattc app register failed, error code = %x\n", __func__, ret);
    }
}

